#include "ch03_pointsprites.h"
#include "LoadShaders.h"
#include "vmath.h"
//#include "vec.h"
#include <GL/wglew.h>

using namespace vmath;

#define POINT_COUNT 4

bool ch03_pointsprites::Init(const EngineDesc &desc)
{
	glViewport(0, 0, desc.Width, desc.Height);
	aspect = float(desc.Height) / float(desc.Width);

	GLenum format;
	int width, height;
	unsigned char * data;

	glEnable(GL_TEXTURE);
	glGenTextures(1, &sprite_texture);
	glBindTexture(GL_TEXTURE_2D, sprite_texture);

	data = vtarga::load_targa("Test/sprite.tga", format, width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, data);

	delete[] data;

	glGenerateMipmap(GL_TEXTURE_2D);

	static ShaderInfo shader_info[] =
	{
		{ GL_VERTEX_SHADER, "Test/pointsprites.vs.glsl", 0 },
		{ GL_FRAGMENT_SHADER, "Test/pointsprites.fs.glsl", 0 },
		{ GL_NONE, NULL, 0 }
	};

	render_prog = LoadShaders(shader_info);

	glUseProgram(render_prog);

	// "model_matrix" is actually an array of 4 matrices
	render_model_matrix_loc = glGetUniformLocation(render_prog, "model_matrix");
	render_projection_matrix_loc = glGetUniformLocation(render_prog, "projection_matrix");

	// A single triangle
	static vec4 * vertex_positions;

	// Set up the vertex attributes
	glGenVertexArrays(1, vao);
	glBindVertexArray(vao[0]);

	glGenBuffers(1, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, POINT_COUNT * sizeof(vec4), NULL, GL_STATIC_DRAW);

	vertex_positions = (vec4 *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
	for ( int n = 0; n < POINT_COUNT; n++ )
	{
		vertex_positions[n] = vec4(random_float() * 2.0f - 1.0f, random_float() * 2.0f - 1.0f, random_float() * 2.0f - 1.0f, 1.0f);
	}
	glUnmapBuffer(GL_ARRAY_BUFFER);

	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)sizeof(vertex_positions));
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
	return true;
}

void ch03_pointsprites::BeginFrame()
{
	float t = float(GetTickCount() & 0x1FFF) / float(0x1FFF);
	static float q = 0.0f;
	static const vec3 X(1.0f, 0.0f, 0.0f);
	static const vec3 Y(0.0f, 1.0f, 0.0f);
	static const vec3 Z(0.0f, 0.0f, 1.0f);

	mat4 model_matrix;

	// Setup
	glEnable(GL_CULL_FACE);
	glDisable(GL_DEPTH_TEST);
	glBindTexture(GL_TEXTURE_2D, sprite_texture);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Activate simple shading program
	glUseProgram(render_prog);

	// Set up the model and projection matrix
	mat4 projection_matrix(frustum(-1.0f, 1.0f, -aspect, aspect, 1.0f, 8.0f));
	glUniformMatrix4fv(render_projection_matrix_loc, 1, GL_FALSE, projection_matrix);

	glEnable(GL_BLEND);	
	glBlendFunc(GL_ONE, GL_ONE);
	glEnable(GL_PROGRAM_POINT_SIZE);
	glPointSize(32.0f);

	// Draw Arrays...
	model_matrix = translate(0.0f, 0.0f, -2.0f) *
		rotate(t * 360.0f, Y) * rotate(t * 720.0f, Z);
	glUniformMatrix4fv(render_model_matrix_loc, 1, GL_FALSE, model_matrix);
	glDrawArrays(GL_POINTS, 0, POINT_COUNT);
}

void ch03_pointsprites::EngFrame()
{

}

void ch03_pointsprites::Destroy()
{
	glUseProgram(0);
	glDeleteProgram(render_prog);
	glDeleteVertexArrays(1, vao);
	glDeleteBuffers(1, vbo);
}